package com.lagou.edu.users.filter;

import com.lagou.edu.users.config.InterceptorPathBean;
import com.lagou.edu.users.service.LagouUsersFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * Token过滤器，如果没有登录，则重定向到登录页面
 */
@Slf4j
@Component
public class TokenFilter implements GlobalFilter, Ordered {

    @Autowired
    private LagouUsersFeignClient lagouUsersFeignClient;

    @Autowired
    private InterceptorPathBean interceptorPathBean;

    private PathMatcher matcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1、取出request，response对象

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 2、取出url,判断是否需要过滤
        String requestUrl = request.getURI().getPath();
        if (excludeMatch(requestUrl)){
            // 2.1、如果排除范围，则直接放行
            return chain.filter(exchange);
        }

        if (includeMatch(requestUrl)) {
            // 2.2、如果是包含范围，则过滤

            // 过滤时先取出token,然后验证token是否有效，如果无效返回401错误
            // 3、取出request中的token是否已经失效。
            List<HttpCookie> lagou_token = request.getCookies().get("lagou_token");
            if (lagou_token != null && !lagou_token.isEmpty()){
                // 已登录
                HttpCookie httpCookie = lagou_token.get(0);
                String token = httpCookie.getValue();
                log.debug("token is : {}",token);

                String info = lagouUsersFeignClient.info(token);
                if (info != null){
                    //  已登录，放行
                    log.debug("info is : {}",info);
                    return chain.filter(exchange);
                } else {
                    log.debug("token is timeout.");
                    return unAuthorizedHandle(response);
                }
            } else {
                // 未登录
                return unAuthorizedHandle(response);
            }
        }

        return chain.filter(exchange);
    }

    /**
     * 返回未认证请求
     * @param response
     * @return
     */
    private Mono<Void> unAuthorizedHandle(ServerHttpResponse response){
        response.setStatusCode(HttpStatus.UNAUTHORIZED);//状态码，未认证

        // 这里都是使用WebFluxAPI进行写操作。
        String data = "Request be denied!";
        DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());

        return response.writeWith(Mono.just(wrap));
    }

    /**
     * 匹配排除过滤url，排除返回true，否则返回false
     * @return
     */
    private boolean excludeMatch(String requestUrl){
        return urlMatch(interceptorPathBean.getExclude(),requestUrl);
    }

    /**
     * 匹配url是否需要过滤。
     * @param requestUrl
     * @return
     */
    private boolean includeMatch(String requestUrl){
        return urlMatch(interceptorPathBean.getInclude(),requestUrl);
    }

    private boolean urlMatch(List<String> list,String requestUrl){
        if (list == null || list.isEmpty()){
            return false;
        }
        for (String patternUrl : list){
            boolean isMatch = match(patternUrl,requestUrl);
            if (isMatch){
                return true;
            }
        }
        return false;
    }

    private boolean match(String patternUrl, String requestUrl){
        if (StringUtils.isEmpty(patternUrl) || StringUtils.isEmpty(requestUrl)){
            return false;
        }
        return matcher.match(patternUrl, requestUrl);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
